/**
 * 
 */
package com.gragra.contextClusterer;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import com.gragra.clustering.ClusteringAlgorithm;
import com.gragra.data.MixingCorpus;
import com.gragra.parseOptions.BooleanOption;
import com.gragra.parseOptions.ListOfIntegerOption;
import com.gragra.parseOptions.ListOfStringsOption;
import com.gragra.parseOptions.OptionInformation;
import com.gragra.parseOptions.Parser;
import com.gragra.sampling.sequentialStructure.WordAndTagHolder;
import com.gragra.sequentiaDataGenerator.BaseGenerator;
import com.gragra.sequentiaDataGenerator.CaseLevelAssigningSegmenter;
import com.gragra.sequentiaDataGenerator.EmptySegmentation;
import com.gragra.sequentiaDataGenerator.HyphenAssigningSegmenter;
import com.gragra.sequentiaDataGenerator.NumericalAssigningSegmenter;
import com.gragra.sequentiaDataGenerator.PunctAssigningSegmenter;
import com.gragra.sequentiaDataGenerator.PunctuationSplitOffSegmenter;
import com.gragra.sequentiaDataGenerator.Segmentation;
import com.gragra.sequentiaDataGenerator.SimpleSuffixAssigningSegmenter;
/**
 * @author Christoph Teichmann
 * 12.05.2013
 */
public abstract class EvaluateLeftRightClustering
{
	/**
	 * 
	 */
	private int suffixLength = 0;
	/**
	 * 
	 */
	private final String useSuffixOption = "useSuffix";
	/**
	 * 
	 */
	private boolean useHyphen = true;
	/**
	 * 
	 */
	private final static String useHyphenOption = "noHyph";
	/**
	 * 
	 */
	private boolean useNum = true;
	/**
	 * 
	 */
	private final static String useNumbersOption = "noNum";
	/**
	 * 
	 */
	private boolean usePunct = true;
	/**
	 * 
	 */
	private final static String usePunctOption = "noP";
	/**
	 * 
	 */
	private int limit = 100;
	/**
	 * 
	 */
	private static final String limitOption = "rank";
	/**
	 * 
	 */
	private int winSize = 1;
	/**
	 * 
	 */
	private static final String winSizeOption = "winSize";
	/**
	 * 
	 */
	private boolean downCase = true;
	/**
	 * 
	 */
	private static final String downCaseOption = "toLower";
	/**
	 * 
	 */
	private String punctuationMarker = null;
	/**
	 * 
	 */
	private boolean	useLabel = false;
	/**
	 * 
	 */
	private String useLabelOption = "uL";
	/**
	 * 
	 */
	private final static String punctTagOption = "punctTag";
	/**
	 * 
	 */
	private int threads = 5;
	/**
	 * 
	 */
	private final static String threadsOpt = "t";
	/**
	 * 
	 * @param input
	 * @param output
	 * @throws IOException
	 * @throws InterruptedException 
	 */
	public void annotate(BufferedReader input,BufferedWriter output, Parser pr) throws IOException, InterruptedException
	{
		this.setOptions(pr);
		BaseGenerator bg = makeGenerator();
		MixingCorpus<WordAndTagHolder> mc = bg.createCorpus(input);
		LeftRightClustering lrc = new LeftRightClustering(this.makeClustering(), mc, this.limit, this.winSize, this.useLabel,threads);
		lrc.cluster();
		lrc.addContextPOSLayerToSelf();
		boolean first = true;
		for(WordAndTagHolder wta : mc)
		{
			if(first)
			{first = false;}
			else
			{output.newLine();}
			output.write(BaseGenerator.transferToString(wta));
		}
	}
	/**
	 * 
	 * @param input
	 * @param output
	 * @throws IOException
	 * @throws InterruptedException 
	 */
	public void annotate(MixingCorpus<WordAndTagHolder> data, Parser pr) throws IOException, InterruptedException
	{
		this.setOptions(pr);
		LeftRightClustering lrc = new LeftRightClustering(this.makeClustering(), data, this.limit, this.winSize, this.useLabel,threads);
		lrc.cluster();
		lrc.addContextPOSLayerToSelf();
	}
	/**
	 * @throws InterruptedException 
	 * 
	 */
	public void writeOutTagAssignments(BufferedReader input, BufferedWriter output, Parser pr) throws IOException, InterruptedException
	{
		this.setOptions(pr);
		BaseGenerator bg = makeGenerator();
		MixingCorpus<WordAndTagHolder> mc = bg.createCorpus(input);
		LeftRightClustering lrc = new LeftRightClustering(this.makeClustering(), mc, this.limit, this.winSize, this.useLabel,threads);
		lrc.cluster();
		lrc.writeOutClusters(output);
	}
	/**
	 * @return
	 */
	protected BaseGenerator makeGenerator()
	{
		Segmentation seg = this.punctuationMarker == null ? new EmptySegmentation() : new PunctuationSplitOffSegmenter(this.punctuationMarker);
		seg = this.downCase ? new CaseLevelAssigningSegmenter(seg) : seg;
		seg = this.useHyphen ? new HyphenAssigningSegmenter(seg) : seg;
		seg = this.useNum ? new NumericalAssigningSegmenter(seg) : seg;
		seg = this.usePunct ? new PunctAssigningSegmenter(seg) : seg;
		seg = this.suffixLength > 0 ? new SimpleSuffixAssigningSegmenter(this.suffixLength, seg) : seg;
		BaseGenerator bg = new BaseGenerator(seg);
		return bg;
	}
	/**
	 * 
	 * @param pr
	 */
	protected void setOptions(Parser pr)
	{
		this.downCase = pr.getInformation(downCaseOption).hasBeenSet();
		OptionInformation oi = pr.getInformation(winSizeOption);
		if(oi.hasBeenSet())
		{this.winSize = ((ListOfIntegerOption) oi).getSettings()[0];}
		oi = pr.getInformation(limitOption);
		if(oi.hasBeenSet())
		{this.limit = ((ListOfIntegerOption) oi).getSettings()[0];}
		oi = pr.getInformation(punctTagOption);
		if(oi.hasBeenSet())
		{this.punctuationMarker = ((ListOfStringsOption) oi).getData()[0];}
		oi = pr.getInformation(this.useLabelOption);
		if(oi.hasBeenSet())
		{this.useLabel = true;}
		this.useHyphen = !pr.getInformation(useHyphenOption).hasBeenSet();
		this.usePunct = !pr.getInformation(usePunctOption).hasBeenSet();
		this.useNum = !pr.getInformation(useNumbersOption).hasBeenSet();
		oi = pr.getInformation(useSuffixOption);
		if(oi.hasBeenSet())
		{this.suffixLength = ((ListOfIntegerOption) oi).getSettings()[0];}
		oi = pr.getInformation(threadsOpt);
		if(oi.hasBeenSet())
		{this.threads = ((ListOfIntegerOption) oi).getSettings()[0];}
	}
	/**
	 * 
	 * @return
	 */
	protected abstract ClusteringAlgorithm makeClustering();
	/**
	 * 
	 * @param to
	 */
	public void addOptions(Parser to)
	{
		to.addOption(downCaseOption, new BooleanOption("set this option in order to apply toLowerCase to all input strings. it will also use the case distribution for words as a feature"));
		to.addOption(winSizeOption, new ListOfIntegerOption("this option can be used to set the size of the window used, standard value is 1"));
		to.addOption(limitOption, new ListOfIntegerOption("this option can be used to set the minimum number of occurrences a frame must have in order to be included into the clustering"));
		to.addOption(punctTagOption, new ListOfStringsOption("if this option is given a tag that can be used for punctuation, then the punctuation will be split off and assigned the given tag"));
		to.addOption(useLabelOption,new BooleanOption("set this option to use the context labels instead of the context words"));
		to.addOption(useHyphenOption, new BooleanOption("set this option to turn off use of the type of hyphenation as a feature in clustering"));
		to.addOption(useNumbersOption, new BooleanOption("set this option to turn off use of the type of digit occcurrences as a feature"));
		to.addOption(usePunctOption, new BooleanOption("set tis option to turn off use of the type of punctuation occurrence"));
		to.addOption(useSuffixOption, new ListOfIntegerOption("use this option to use the last n letters as a suffix feature, n is an argument to the option"));
		to.addOption(threadsOpt, new ListOfIntegerOption("sets the number of parallel runs used"));
	}
	/**
	 * @return the threads
	 */
	protected int getThreads()
	{return this.threads;}
}